using System;
using System.Collections.Generic;
using RootMotion.FinalIK;
using UnityEngine;

public class KineticAnimationImport : MonoBehaviour
{
	public class ImportAnimationState
	{
		public MoveAnimationInfo importingAnimation;

		public float duration;

		public Vector3 positionChange;

		public Quaternion rotationChange;

		public Vector3 lastRacketCenterDeltaPosition;

		public Quaternion lastRacketCenterDeltaRotation;

		public Quaternion lastHitHandDeltaRotation;

		public float lastDeltaTime;

		public float prevNormTime;
	}

	private Vector3 initialPosition;

	private Quaternion initialRotation;

	private Vector3 initialScale;

	public List<HitAnimationsStateEnum> compareHits = new List<HitAnimationsStateEnum>();

	public List<HitAnimationsStateEnum> importHits = new List<HitAnimationsStateEnum>();

	private Animator _cachedAnimator;

	[Header("Setup params")]
	public Transform hitHandTransform;

	public Transform racketCenterTransform;

	[Header("Preview parameters")]
	[Range(0.02f, 1f)]
	public float moveTimeScale = 1f;

	public float durationBetweenLoop = 0.5f;

	[Range(-1f, 1f)]
	public float xHitAdjust;

	[Range(-1f, 1f)]
	public float yHitAdjust;

	[Range(-1f, 1f)]
	public float zHitAdjust;

	[Range(-1f, 1f)]
	public float xAdjust;

	[Range(-1f, 1f)]
	public float zAdjust;

	[Range(-1f, 1f)]
	public float angleAdjust;

	public bool useSmoothStep;

	[Header("Import parameters")]
	[Range(0.02f, 1f)]
	public float importTimeScale = 0.5f;

	public KineticAnimationsStateEnum animEnum;

	public bool doLoopAnim;

	private ImportAnimationState importingAnimationState = new ImportAnimationState();

	private Action onDoneImportingAnimation;

	private KineticElementMove moveElement = new KineticElementMove();

	[NonSerialized]
	public bool moveElementPlaying;

	private float waitingBetweenPlaysTime;

	public Animator cachedAnimator
	{
		get
		{
			if (_cachedAnimator == null)
			{
				_cachedAnimator = GetComponent<Animator>();
			}
			return _cachedAnimator;
		}
	}

	public MoveAnimationInfo moveAnimInfo
	{
		get
		{
			return ScriptableObjectSingleton<KineticAnimationInfoDB>.instance.GetOrCreateAnimationByEnum(animEnum) as MoveAnimationInfo;
		}
	}

	public HitAnimationInfo hitAnimInfo
	{
		get
		{
			return ScriptableObjectSingleton<KineticAnimationInfoDB>.instance.GetOrCreateAnimationByEnum(animEnum) as HitAnimationInfo;
		}
	}

	private MoveAnimationInfo importingAnimation
	{
		get
		{
			return importingAnimationState.importingAnimation;
		}
		set
		{
			importingAnimationState = new ImportAnimationState();
			importingAnimationState.importingAnimation = value;
		}
	}

	public FullBodyBipedIK ik
	{
		get
		{
			return GetComponent<FullBodyBipedIK>();
		}
	}

	public KineticElementMove GetMoveElement()
	{
		return moveElement;
	}

	private void Start()
	{
		initialPosition = base.transform.position;
		initialRotation = base.transform.rotation;
		initialScale = base.transform.localScale;
		moveElement.startPosition = initialPosition;
		moveElement.startRotation = initialRotation;
	}

	private void ResetTransformToInitial()
	{
		base.transform.position = initialPosition;
		base.transform.rotation = initialRotation;
		base.transform.localScale = initialScale;
	}

	public void ImportAnimation(MoveAnimationInfo info, Action onDone)
	{
		if (!Application.isPlaying)
		{
			onDone();
			return;
		}
		onDoneImportingAnimation = onDone;
		ResetTransformToInitial();
		cachedAnimator.Play(info.animatorStateName, 0, 0f);
		Time.timeScale = importTimeScale;
		importingAnimation = info;
		info.checkpoints.Clear();
	}

	private void UpdateImportAnimation()
	{
		AnimatorStateInfo currentAnimatorStateInfo = cachedAnimator.GetCurrentAnimatorStateInfo(0);
		if (currentAnimatorStateInfo.shortNameHash != Animator.StringToHash(importingAnimation.animatorStateName))
		{
			return;
		}
		HitAnimationInfo hitAnimationInfo = importingAnimation as HitAnimationInfo;
		float duration = importingAnimationState.duration;
		importingAnimationState.duration += Time.deltaTime;
		float num = ((!(importingAnimation.adjustmentsTimeWindow.min > 0f)) ? (importingAnimation.clipLength * 0.2f) : (importingAnimation.adjustmentsTimeWindow.min * 0.9f));
		if (duration < num && importingAnimationState.duration >= num)
		{
			KineticAnimationInfo.CheckpointInfo checkpointInfo = new KineticAnimationInfo.CheckpointInfo();
			checkpointInfo.positionChange = GetPositionChange();
			checkpointInfo.rotationChange = GetRotationChange();
			checkpointInfo.hitHandPositionChange = GetHitHandPositionChange();
			checkpointInfo.time = importingAnimationState.duration;
			importingAnimation.checkpoints.Add(checkpointInfo);
		}
		if (hitAnimationInfo != null)
		{
			duration = importingAnimationState.prevNormTime * hitAnimationInfo.clipLength;
			float num2 = currentAnimatorStateInfo.normalizedTime * hitAnimationInfo.clipLength;
			if (duration <= hitAnimationInfo.hitTime && num2 > hitAnimationInfo.hitTime)
			{
				float t = (hitAnimInfo.hitTime - duration) / Time.deltaTime;
				Vector3 hitPosition = Quaternion.Inverse(initialRotation) * (racketCenterTransform.position - Vector3.Lerp(importingAnimationState.lastRacketCenterDeltaPosition, Vector3.zero, t) - initialPosition);
				Quaternion handRotationAtHit = Quaternion.Inverse(initialRotation) * Quaternion.Inverse(Quaternion.Lerp(importingAnimationState.lastHitHandDeltaRotation, Quaternion.identity, t)) * hitHandTransform.rotation;
				Quaternion racketRotationAtHit = Quaternion.Inverse(initialRotation) * Quaternion.Inverse(Quaternion.Lerp(importingAnimationState.lastRacketCenterDeltaRotation, Quaternion.identity, t)) * racketCenterTransform.rotation;
				hitAnimationInfo.hitPosition = hitPosition;
				hitAnimationInfo.handRotationAtHit = handRotationAtHit;
				hitAnimationInfo.racketRotationAtHit = racketRotationAtHit;
			}
		}
		if (currentAnimatorStateInfo.normalizedTime >= 1f && importingAnimationState.duration >= importingAnimation.clipLength * 1.25f)
		{
			OnUpdateImportAnimationDone();
		}
		importingAnimationState.prevNormTime = currentAnimatorStateInfo.normalizedTime;
	}

	private Vector3 GetPositionChange()
	{
		return Quaternion.Inverse(initialRotation) * (base.transform.position - initialPosition);
	}

	private Vector3 GetHitHandPositionChange()
	{
		return Quaternion.Inverse(initialRotation) * (hitHandTransform.position - initialPosition);
	}

	private Quaternion GetRotationChange()
	{
		return base.transform.rotation * Quaternion.Inverse(initialRotation);
	}

	private void OnUpdateImportAnimationDone()
	{
		Vector3 positionChange = GetPositionChange();
		Quaternion rotationChange = GetRotationChange();
		importingAnimation.positionChange = positionChange;
		importingAnimation.rotationChange = rotationChange;
		importingAnimation = null;
		if (onDoneImportingAnimation != null)
		{
			onDoneImportingAnimation();
		}
	}

	public Vector3 StartMovePosition()
	{
		HitAnimationInfo hitAnimationInfo = moveElement.animInfo as HitAnimationInfo;
		if (hitAnimationInfo == null)
		{
			return initialPosition;
		}
		Vector3 result = initialPosition;
		result.z = Mathf.Sign(result.z) * (Table.halfLength + hitAnimationInfo.minDistanceFromTable);
		return result;
	}

	public void PlayMoveElement()
	{
		moveElementPlaying = true;
		waitingBetweenPlaysTime = 0f;
		moveElement.animInfo = ScriptableObjectSingleton<KineticAnimationInfoDB>.instance.GetAnimation(animEnum.ToString()) as MoveAnimationInfo;
		moveElement.startPosition = StartMovePosition();
		Time.timeScale = moveTimeScale;
		if (!moveElement.isActive)
		{
			moveElement.OnStart(base.transform);
		}
	}

	public void StopMoveElement()
	{
		moveElementPlaying = false;
		ResetTransformToInitial();
		cachedAnimator.Play("Idle");
	}

	public void PauseMoveElement()
	{
		moveElementPlaying = false;
		Time.timeScale = 0f;
	}

	public void OnAnimatorMove()
	{
		if (importingAnimation != null)
		{
			Vector3 vector = Vector3.zero;
			Quaternion rotation = Quaternion.identity;
			Quaternion rotation2 = Quaternion.identity;
			if (racketCenterTransform != null)
			{
				vector = racketCenterTransform.position;
				rotation2 = racketCenterTransform.rotation;
			}
			if (hitHandTransform != null)
			{
				rotation = hitHandTransform.rotation;
			}
			importingAnimationState.lastDeltaTime = Time.deltaTime;
			base.transform.position += cachedAnimator.deltaPosition;
			base.transform.rotation = cachedAnimator.deltaRotation * base.transform.rotation;
			if (racketCenterTransform != null)
			{
				importingAnimationState.lastRacketCenterDeltaPosition = racketCenterTransform.position - vector;
				importingAnimationState.lastRacketCenterDeltaRotation = Quaternion.Inverse(rotation2) * racketCenterTransform.rotation;
			}
			if (hitHandTransform != null)
			{
				importingAnimationState.lastHitHandDeltaRotation = Quaternion.Inverse(rotation) * hitHandTransform.rotation;
			}
		}
		else if (moveElementPlaying)
		{
			moveElement.OnAnimatorMove();
			Time.timeScale = moveTimeScale;
		}
		else
		{
			base.transform.position += cachedAnimator.deltaPosition;
			base.transform.rotation = cachedAnimator.deltaRotation * base.transform.rotation;
		}
	}

	public void Update()
	{
		moveElement.useSmoothStep = useSmoothStep;
		float x = moveAnimInfo.xAdjustRange.LerpMinMax(xAdjust);
		float z = moveAnimInfo.zAdjustRange.LerpMinMax(zAdjust);
		moveElement.adjustPosition = moveElement.startRotation * new Vector3(x, 0f, z);
		moveElement.adjustAngle = moveAnimInfo.angleAdjustRange.LerpMinMax(angleAdjust);
	}

	public void LateUpdate()
	{
		if (importingAnimation != null)
		{
			UpdateImportAnimation();
			return;
		}
		moveElement.OnLateUpdate();
		if (!moveElementPlaying)
		{
			return;
		}
		if (!moveElement.isActive)
		{
			ik.enabled = false;
			waitingBetweenPlaysTime += Time.deltaTime;
			if (waitingBetweenPlaysTime > durationBetweenLoop)
			{
				PlayMoveElement();
			}
		}
		else if (hitAnimInfo != null)
		{
			ik.enabled = true;
			HitAnimationInfo hitAnimationInfo = hitAnimInfo;
			Quaternion startRotation = moveElement.startRotation;
			Vector3 vector = StartMovePosition();
			Vector3 vector2 = vector + startRotation * hitAnimationInfo.hitPosition;
			Vector3 vector3 = vector2 + startRotation * (Vector3.right * hitAnimationInfo.xHitAdjustRange.LerpMinMax(xHitAdjust) + Vector3.up * hitAnimationInfo.yHitAdjustRange.LerpMinMax(yHitAdjust) + Vector3.forward * hitAnimationInfo.zHitAdjustRange.LerpMinMax(zHitAdjust));
			Vector3 vector4 = vector3 - vector2;
			Vector3 direction = Quaternion.Inverse(hitAnimationInfo.handRotationAtHit * startRotation) * vector4;
			Vector3 a = hitHandTransform.TransformDirection(direction);
			float @float = cachedAnimator.GetFloat("IKWeight");
			ik.solver.rightHandEffector.positionWeight = @float;
			Vector3 position = hitHandTransform.position + Vector3.Lerp(a, vector4, ScriptableObjectSingleton<KineticAnimationInfoDB>.instance.globalPosInfluenceWithIKWeight.Evaluate(@float));
			ik.solver.rightHandEffector.position = position;
		}
	}
}
